package com.coupon.settlement.executor;

import com.alibaba.fastjson.JSON;
import com.coupon.common.vo.GoodsInfo;
import com.coupon.common.vo.SettlementInfo;
import org.apache.commons.collections4.CollectionUtils;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author 王哲
 * @Contact 1121586359@qq.com
 * @ClassName AbstractExecutor.java
 * @create 2023年06月27日 上午11:15
 * @Description 规则执行器抽象类
 * @Version V1.0
 */

public abstract class AbstractExecutor {

    /**
     * 校验商品类型与优惠券是否匹配
     * 1.这里实现的是单品类优惠券的校验，多品类优惠券重载此方法
     * 2.商品只需要有一个优惠券要求的商品类型去匹配就可以
     *
     * @param settlement
     * @return
     */
    protected boolean isGoodsTypeSatisfy(SettlementInfo settlement) {

        List<Integer> goodsType = settlement.getGoodsInfos().stream()
                .map(GoodsInfo::getType)
                .collect(Collectors.toList());

        List<Integer> templateGoodsType = JSON.parseObject(
                settlement.getCouponAndTemplateInfos().
                get(0).getTemplateSDK().getRule().getUsage().getGoodsType(),
                List.class);

        return CollectionUtils.isNotEmpty(
                // 只要有一个匹配就可以
                CollectionUtils.intersection(goodsType, templateGoodsType)
        );
    }

    /**
     * 处理商品类型与优惠券限制不匹配的情况
     * @param settlement {@link SettlementInfo} 用户传递的结算信息
     * @param goodsSum 商品总价
     * @return {@link SettlementInfo} 已经修改过的结算信息
     */
    protected SettlementInfo processGoodsTypeNotSatisfy(
            SettlementInfo settlement, double goodsSum) {

        boolean isGoodsTypeSatisfy = isGoodsTypeSatisfy(settlement);

        // 当商品类型不满足时，直接返回总价，并清空可使用优惠券列表
        if (!isGoodsTypeSatisfy) {
            settlement.setCost(goodsSum);
            settlement.setCouponAndTemplateInfos(Collections.emptyList());
            return settlement;
        }
        return null;
    }

    /**
     * 商品总价
     * @param goodsInfos {@link GoodsInfo} 商品信息
     * @return 商品总价
     */
    protected double goodsCostSum(List<GoodsInfo> goodsInfos) {

        return goodsInfos.stream().mapToDouble(
                g -> g.getPrice() * g.getCount()
        ).sum();
    }

    /**
     * 保留两位小数
     * @param value
     * @return
     */
    protected double retain2Decimals(double value) {

        return new BigDecimal(value).setScale(
                2, BigDecimal.ROUND_HALF_UP
        ).doubleValue();
    }

    /**
     * 最小支付费用
     * @return
     */
    protected double minCost() {

        return 0.1;
    }

}
